﻿/* Copyright (c) 2015 Slava Naumenko - http://m4w.codeplex.com */

using Microsoft.SharePoint;
using Microsoft.SharePoint.Deployment;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowServices;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Web.Services;
using System.Xml;

namespace M4W.ASM.Services
{
    [WebService(Namespace = "M4W.ASM.Services")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.Web.Script.Services.ScriptService]
    [System.ComponentModel.ToolboxItem(false)]
    public class Web : System.Web.Services.WebService
    {
        [WebMethod]
        public string Create(string Uri, string Title, string Description, string Template, string InheritPermissions, string InheritTopLinks)
        {
            string result = "";
            try
            {
                result = WebCreate.Invoke(Uri, Title, Description, Template, InheritPermissions, InheritTopLinks);
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string Export(string ExpPath)
        {
            string result = "";
            try
            {
                result = WebExport.Invoke(ExpPath);
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetOwnerBox(string Owner)
        {
            string result = "";
            try
            {
                WebSetOwnerBox.Invoke(Owner);

                result = "Owner '" + Owner + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetAuthor(string Author)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("Author", Author);

                result = "Author '" + Author + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetTitle(string Title)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("Title", Title);

                result = "Title '" + Title + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetDescription(string Description)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("Description", Description);

                result = "Description '" + Description + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetMasterpage(string Masterpage)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("Masterpage", Masterpage);

                result = "Masterpage '" + Masterpage + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string EnableInheritMasterpage(string InheritMasterpage)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("InheritMasterpage", InheritMasterpage);

                result = "Inherit masterpage '" + InheritMasterpage + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetAlternateCSS(string AlternateCSS)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("AlternateCSS", AlternateCSS);

                result = "Alternate CSS '" + AlternateCSS + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string SetAccessRequestEmail(string AccessRequestEmail)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("AccessRequestEmail", AccessRequestEmail);

                result = "Access request e-mail '" + AccessRequestEmail + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string EnableQuickLaunch(string QuickLaunchEnabled)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("QuickLaunchEnabled", QuickLaunchEnabled);

                result = "Quick launch '" + QuickLaunchEnabled + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string EnableTreeView(string TreeViewEnabled)
        {
            string result = "";
            try
            {
                WebSetProperty.Invoke("TreeViewEnabled", TreeViewEnabled);

                result = "Tree view '" + TreeViewEnabled + "'.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string FeatureActivate(string Id)
        {
            string result = "";
            try
            {
                WebFeatureManage.Invoke(Id, "activate");

                result = "Feature '" + Id + "' activated.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string FeatureDeactivate(string Id)
        {
            string result = "";
            try
            {
                WebFeatureManage.Invoke(Id, "deactivate");

                result = "Feature '" + Id + "' deactivated.";
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }

        [WebMethod]
        public string WorkflowStart(string Workflow)
        {
            string result = "";
            try
            {
                result = WebWorkflowStart.Invoke(Workflow);
            }
            catch (Exception ex)
            {
                result = ex.Message.ToString();
            }
            return result;
        }
    }

    // Invocations

    internal static class WebCreate
    {
        internal static string Invoke(string Uri, string Title, string Description, string Template, string InheritPermissions, string InheritTopLinks)
        {
            string result = "";

            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPSite parentSite = site;
                    SPWeb parentWeb = web;
                    SPWeb newWeb = null;
                    string newWebRelativeUrl = Uri;

                    try
                    {
                        if (String.IsNullOrEmpty(Description)) { Description = ""; }
                        if (String.IsNullOrEmpty(Template)) { Template = "STS#0"; }

                        parentWeb.AllowUnsafeUpdates = true;

                        newWeb = parentWeb.Webs.Add(newWebRelativeUrl, Title, Description, (uint)parentWeb.Locale.LCID, Template, !Convert.ToBoolean(InheritPermissions), false);

                        parentWeb.AllowUnsafeUpdates = false;

                        if (Convert.ToBoolean(InheritTopLinks))
                        {
                            newWeb.Navigation.UseShared = true;
                            newWeb.Update();
                        }

                        result = newWeb.Url;
                    }
                    catch (Exception ex)
                    {
                        result = ex.Message;
                    }
                    finally
                    {
                        if (newWeb != null) newWeb.Dispose();
                    }
                }
            }

            return result;
        }
    }

    internal static class WebSetOwnerBox
    {
        internal static void Invoke(string Owner)
        {
            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;

                    SPUser user = web.EnsureUser(Owner);

                    string userName = user.Name;
                    string userEmail = user.Email.ToLower();
                    string userFooter = user.Email.ToLower();

                    string homeUrl = "";
                    if (web.RootFolder.WelcomePage != null)
                    {
                        homeUrl = web.RootFolder.WelcomePage;
                    }

                    if (homeUrl.Contains("SitePages"))
                    {
                        // Team Site

                        homeUrl = web.ServerRelativeUrl + homeUrl;
                        SPFile homePage = web.GetFile(homeUrl);

                        if (homePage.Exists)
                        {
                            if (homePage.Item["WikiField"] != null)
                            {
                                homePage.Item["WikiField"] = WebSetOwnerBox.ModifyOwner(homePage.Item["WikiField"].ToString(), userName, userEmail, userFooter);
                                homePage.Item.Update();
                            }
                        }
                    }
                    else
                    {
                        // Blog and Meeting

                        homeUrl = "default.aspx";

                        using (SPLimitedWebPartManager wm = web.GetLimitedWebPartManager(homeUrl, System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared))
                        {
                            System.Web.UI.WebControls.WebParts.WebPart wp = null;

                            foreach (System.Web.UI.WebControls.WebParts.WebPart wp1 in wm.WebParts)
                            {
                                if (wp1.Title.Contains("Site Owner Box"))
                                {
                                    wp = wp1;
                                    break;
                                }
                            }

                            if (wp != null)
                            {
                                ContentEditorWebPart ownerBox = (ContentEditorWebPart)wp;

                                XmlDocument xmlDoc = new XmlDocument();
                                XmlElement xmlElement = xmlDoc.CreateElement("HtmlContent");

                                xmlElement.InnerText = ModifyOwner(ownerBox.Content.InnerText, userName, userEmail, userFooter);

                                ownerBox.Content = xmlElement;

                                wm.SaveChanges(ownerBox);
                            }
                        }
                    }

                    web.AllowUnsafeUpdates = false;
                }
            }
        }

        internal static string ModifyOwner(string val, string name, string email, string footer)
        {
            string pattern = "";
            string replacement = "";

            pattern = "<span class=.ms-rteFontSize-3 ms-rteThemeForeColor-8-4.>.*</span></a><br";
            replacement = "<span class=\"ms-rteFontSize-3 ms-rteThemeForeColor-8-4\">" + name + "</span></a><br";
            val = Regex.Replace(val, pattern, replacement, RegexOptions.Singleline);

            pattern = "</span></td>.*<a href=.mailto.*<span class=.ms-rteFontSize-3";
            replacement = "</span></td><td align=\"center\" valign=\"middle\"><a href=\"mailto:" + email + "\"><span class=\"ms-rteFontSize-3";
            val = Regex.Replace(val, pattern, replacement, RegexOptions.Singleline);

            pattern = "</span></a>.*<a href=.mailto.*<span class=.ms-rteFontSize-1";
            replacement = "</span></a><br><a href=\"mailto:" + email + "\"><span class=\"ms-rteFontSize-1";
            val = Regex.Replace(val, pattern, replacement, RegexOptions.Singleline);

            pattern = "<span class=.ms-rteFontSize-1 ms-rteThemeForeColor-5-4.>.*</span></a></td>";
            replacement = "<span class=\"ms-rteFontSize-1 ms-rteThemeForeColor-5-4\">" + footer + "</span></a></td>";
            val = Regex.Replace(val, pattern, replacement, RegexOptions.Singleline);

            return val;
        }
    }

    internal static class WebSetProperty
    {
        internal static void Invoke(string property, string value)
        {
            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;

                    switch (property)
                    {
                        case "Author":
                            web.Author = web.EnsureUser(value);
                            break;
                        case "Title":
                            web.Title = value;
                            break;
                        case "Description":
                            web.Description = value;
                            break;
                        case "Masterpage":
                            Uri masterUri = new Uri(web.Site.RootWeb.Url + value);
                            web.MasterUrl = masterUri.AbsolutePath;
                            web.CustomMasterUrl = masterUri.AbsolutePath;
                            break;
                        case "InheritMasterpage":
                            web.AllProperties["__InheritsMasterUrl"] = value;
                            web.AllProperties["__InheritsCustomMasterUrl"] = value;
                            break;
                        case "AlternateCSS":
                            web.AlternateCssUrl = value;
                            break;
                        case "AccessRequestEmail":
                            web.RequestAccessEmail = value;
                            break;
                        case "QuickLaunchEnabled":
                            web.QuickLaunchEnabled = Convert.ToBoolean(value);
                            break;
                        case "TreeViewEnabled":
                            web.TreeViewEnabled = Convert.ToBoolean(value);
                            break;
                        default:
                            throw new Exception("'" + property + "' is not implemented.");
                    }

                    web.Update();

                    web.AllowUnsafeUpdates = false;
                }
            }
        }
    }

    internal static class WebFeatureManage
    {
        internal static void Invoke(string Id, string operation)
        {
            Guid fId = new Guid("{" + Id + "}");

            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;

                    if (operation == "activate")
                    {
                        SPFeature aFeature = null;
                        string FeatureError = "";

                        try
                        {
                            aFeature = web.Features.Add(fId, false, SPFeatureDefinitionScope.Site);
                        }
                        catch (Exception ex)
                        {
                            FeatureError = ex.Message;
                        }

                        try
                        {
                            if (aFeature == null)
                            {
                                web.Features.Add(fId);
                            }
                        }
                        catch (Exception ex)
                        {
                            if (FeatureError == "" || FeatureError.Contains("not installed")) { FeatureError = ex.Message; }

                            throw new Exception(FeatureError);
                        }
                    }
                    else if (operation == "deactivate")
                    {
                        web.Features.Remove(fId);
                    }

                    web.AllowUnsafeUpdates = false;
                }
            }
        }
    }

    internal static class WebWorkflowStart
    {
        internal static string Invoke(string Workflow)
        {
            string result = "";

            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;

                    string mode = "";

                    // 2010

                    SPWorkflowAssociation workflowAssociation = web.WorkflowAssociations.GetAssociationByName(Workflow, System.Threading.Thread.CurrentThread.CurrentCulture);

                    // 2013

                    WorkflowServicesManager workflowServicesManager = new Microsoft.SharePoint.WorkflowServices.WorkflowServicesManager(web);
                    WorkflowSubscription workflowSubscription = null;

                    if (workflowAssociation != null)
                    {
                        mode = "2010";
                    }
                    else
                    {
                        foreach (WorkflowSubscription subscription in workflowServicesManager.GetWorkflowSubscriptionService().EnumerateSubscriptions())
                        {
                            if (subscription.Name == Workflow)
                            {
                                workflowSubscription = subscription;
                                break;
                            }
                        }

                        if (workflowSubscription != null)
                        {
                            mode = "2013";
                        }
                    }

                    switch (mode)
                    {
                        case "2010":
                            if (workflowAssociation.RunningInstances == 0)
                            {
                                site.WorkflowManager.StartWorkflow(null, workflowAssociation, "", SPWorkflowRunOptions.Asynchronous);
                                result = "2010 workflow '" + Workflow + "' started.";
                            }
                            else
                            {
                                result = "2010 workflow '" + Workflow + "' is already running.";
                            }
                            break;
                        case "2013":
                            WorkflowInstanceService workflowInstanceService = workflowServicesManager.GetWorkflowInstanceService();

                            if (workflowInstanceService.CountInstancesWithStatus(workflowSubscription, WorkflowStatus.Started) == 0)
                            {
                                workflowInstanceService.StartWorkflow(workflowSubscription, new Dictionary<string, object>());
                                result = "2013 workflow '" + Workflow + "' started.";
                            }
                            else
                            {
                                result = "2013 workflow '" + Workflow + "' is already running.";
                            }
                            break;
                        default:
                            result = "Workflow '" + Workflow + "' could not be found.";
                            break;
                    }

                    web.AllowUnsafeUpdates = false;
                }
            }

            return result;
        }
    }

    internal static class WebExport
    {
        internal static string Invoke(string ExpPath)
        {
            string result = "";

            string curl = Helper.GetCurrentUrl();

            using (SPSite site = new SPSite(curl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    web.AllowUnsafeUpdates = true;

                    string expfile = ExpPath + "\\" + web.Title + ".cmp";

                    if (ExportWeb(web, ExpPath))
                    {
                        result = "Web has been exported: " + web.Url + " '" + expfile + "'.";
                    }
                    else
                    {
                        result = "File verification '" + expfile + "' failed.";
                    }

                    web.AllowUnsafeUpdates = false;
                }
            }

            return result;
        }

        internal static bool ExportWeb(SPWeb web, string ExpPath)
        {
            string expfile = ExpPath + "\\" + web.Title + ".cmp";

            SPExportSettings settings = new SPExportSettings();
            settings.SiteUrl = web.Url;
            settings.FileLocation = @ExpPath;
            settings.BaseFileName = web.Title + ".cmp";
            settings.FileCompression = true;
            settings.ExportMethod = SPExportMethodType.ExportAll;
            SPExport export = new SPExport(settings);
            export.Run();

            return Helper.VerifyFile(expfile);
        }
    }
}